﻿/**************************************************************

项目名称 :ThinkWide数据访问基础库
版权所有 (c) 2009 ThinkWide
+-------------------------------------------------------------
项目: ORMapping服务类


版本: 1


创建日期:2010-5-3


作者: 章称

+-------------------------------------------------------------
描述:z

更新:   2010-5-3

ToDo:

***************************************************************/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Reflection;
using System.Collections;

namespace MF.Data.ORMapping
{

    /// <summary>
    /// 全局管理集对象
    /// </summary>
    public class MFORMappingGlobe
    {
        private static MFDataAdapter dataAdapter=null;

        public static MFDataAdapter DataAdapter
        {
            get 
            {
                if (dataAdapter == null) Init(string.Empty);
                return dataAdapter;
            }

        }

        public static bool Init(string providerName)
        {
            dataAdapter = new MFDataAdapter(providerName);
            return dataAdapter != null;
        }
    }


    public enum MFORMappingState {Unchanged,Added,Modified,Deleted,Detached}


    public interface IMFActiveRecordBase
    {
        MFORMappingState State { get; set; }
        void Insert();
        void Update();
        void Delete();
    }


    public abstract class MFActiveRecordBaseX: MarshalByRefObject
    {

    }


    public class MFActiveRecordResource
    {
        public const string MFActiveRecordBase = "MFActiveRecordBase";
    }

    
    /// <summary>
    /// ORM基类
    /// </summary>
    /// <typeparam name="T"></typeparam>
    [Serializable]
    public abstract class MFActiveRecordBase<T> : MFActiveRecordBaseX,IMFActiveRecordBase where T : MFActiveRecordBase<T>, new()
    {
        [MFNotField]
        public MFORMappingState State { get; set; }

        protected MFActiveRecordBase()
        {

        }

        public void Insert()
        {
            List<T> list = new List<T>();
            this.State = MFORMappingState.Added;
            list.Add((T)this);

            DataSet ds = MFDataTransfer.GetDataSet(list);
            MFORMappingGlobe.DataAdapter.SaveDataTable(ds.Tables[0]);
            this.State = MFORMappingState.Unchanged;
        }

        public void Update()
        {
            List<T> list= new List<T>();
            this.State = MFORMappingState.Modified;
            list.Add((T)this);

            DataSet ds=MFDataTransfer.GetDataSet(list);
            MFORMappingGlobe.DataAdapter.SaveDataTable(ds.Tables[0]);
            this.State = MFORMappingState.Unchanged;
        }

        public void Delete()
        {
            
            string sTableName = GetTableName<T>(typeof(T));
            string sWhere = string.Empty;
            Dictionary<string, string> keyList = MFDataTransfer.GetKeyList(this);

            if (keyList.Count == 0) throw new Exception("The ORMapping Class Need Attribute of PrimaryKey");

            foreach (var item in keyList)
            {
                if (!string.IsNullOrEmpty(sWhere)) sWhere += MFSQLBase.cAnd;

                object pValue = MFReflect.GetProperty(this, item.Value);

                if (pValue.GetType() == typeof(Guid) || pValue.GetType() == typeof(String))
                {
                    sWhere += string.Format("{0} = '{1}' ", item.Key, MFReflect.GetProperty(this, item.Value));
                }
                else
                    sWhere += item.Key + MFSQLSelect.cEqual + MFReflect.GetProperty(this, item.Value);
            }

            if (!string.IsNullOrEmpty(sWhere)) sWhere = MFSQLBase.cWhere + sWhere;

            string sSQL;

            sSQL = string.Format(MFSQLDelete.cDelete, sTableName , sWhere);


            int i = MFORMappingGlobe.DataAdapter.ExecuteSQL(sSQL);
            this.State = MFORMappingState.Unchanged;

        }


        private static string GetTableName<T>(Type type)
        {
            string sTableName = typeof(T).Name;

            foreach (object AClassAtt in type.GetCustomAttributes(false))
            {
                if (AClassAtt is MFTableAttribute)
                {
                    return (AClassAtt as MFTableAttribute).TableName ?? sTableName;

                }

                if (AClassAtt is MFViewAttribute)
                {
                    return (AClassAtt as MFViewAttribute).TableName ?? sTableName;
                }
            }

            return sTableName;
        }

        private static string GetTableViewName<T>(Type type)
        {
            string sTableName = typeof(T).Name;

            foreach (object AClassAtt in type.GetCustomAttributes(false))
            {
                if (AClassAtt is MFTableAttribute)
                {
                    return (AClassAtt as MFTableAttribute).TableName ?? sTableName;
                }

                if (AClassAtt is MFViewAttribute)
                {
                    return (AClassAtt as MFViewAttribute).ViewName ?? sTableName;
                }
            }

            return sTableName;
        }

        public static List<T> FindAll()
        {
            return FindAll(null, null,null);
        }

        public static T FindOne(string where, params object[] args)
        {
            List<T> list = FindAll(where,args);
            if (list.Count > 0)
                return list[0];
            else
                return null;
        }

        public static List<T> FindAll(string where,params object[] args)
        {

            return FindAll(where,null,args);
        }

        public static List<T> FindAllOrderBy(string orderBy)
        {
            return FindAll(null, orderBy, null);
        }

        public static List<T> FindAll(MFARCondition condotion)
        {
            return FindAll();
        }

        public static List<T> FindAll(string where,string orderBy, params object[] args)
        {
            string sSQL;

            MFDataClassSQLAttInfo cInfo=MFDataTransfer.GetClassSQLInfo<T>();
            
            string rWhere = MFSQLSelect.GetSQLWhereCondition(where, cInfo.Where);
            string rOrderBy = MFSQLSelect.GetSQLOrderByCondition(orderBy, cInfo.OrderBy);


            string sTableName = string.Empty;

            sTableName = GetTableViewName<T>(typeof(T));

            if (!string.IsNullOrEmpty(cInfo.SQL))
            {
                sSQL = cInfo.SQL;
                
            }
            else
            {
                sSQL = string.Format(MFSQLSelect.cSelectSimple, sTableName);
                
            }

            sSQL = sSQL + MFSQLBase.cSpace + MFSQLSelect.GetSQLSelect(rWhere, args) + MFSQLBase.cSpace + rOrderBy;


            DataTable dt = MFORMappingGlobe.DataAdapter.GetDataSet(sSQL).Tables[0];
            List<T> list = MFDataTransfer.GetList<T>(dt);

            return list;
        }

        public override string ToString()
        {
            return base.ToString();
        }

        private void LoadTransaction()
        {

        }

        private T GetEntity()
        {
            return this as T;
        }


        public static T FindByPrimaryKey(params object[] args)
        {
            List<string> list = MFDataTransfer.GetPrimaryKeyFieldNames<T>();
            string where=string.Empty;
            string condition="{0}=?";
            foreach (string item in list)
            {
                string str = string.Format(condition, item);
                where += string.IsNullOrEmpty(where) ? str : MFSQLSelect.cAnd + str;
            }

            return FindOne(where, args);
        }


        public static IList FastLazyLoadDetail(string relationName,object masterValue)
        {
            object list = null;
            MFDataRelationAttInfo rInfo = MFDataTransfer.GetRelationInfo(typeof(T), relationName);
            Object mValue = masterValue;
            string where = string.Empty;
            string orderby = string.Empty;
            where = rInfo.Master.Where;
            orderby = rInfo.Master.OrderBy;

            if (string.IsNullOrEmpty(where))
                where = string.Format("{0}=?", rInfo.Master.DetailColumnKey);
            else
                where = where + string.Format(" and {0}=? ", rInfo.Master.DetailColumnKey);


            list = MFActiveRecordReflect.FindList(rInfo.Master.DetailType, where, mValue);
            
            return (IList)list;
        }

        public IList LazyLoadDetail(string relationName)
        {
            object list = null;
            MFDataRelationAttInfo rInfo = MFDataTransfer.GetRelationInfo(this.GetType(), relationName);
            Object mValue = MFReflect.GetProperty(this, rInfo.Detail.MasterColumnKey);
            string where=string.Empty;
            string orderby=string.Empty;
            where = rInfo.Master.Where;
            orderby=rInfo.Master.OrderBy;

            if (string.IsNullOrEmpty(where)) 
                where=string.Format("{0}=?",rInfo.Master.DetailColumnKey);
            else
                where =where+ string.Format(" and {0}=? ", rInfo.Master.DetailColumnKey);

            list = MFActiveRecordReflect.FindList(rInfo.Master.DetailType, where, orderby,mValue);

            foreach (object item in (IList)list)
            {
                MFReflect.SetProperty(item, rInfo.DetailPropertyName, this);
            }
            return (IList)list;
        }

    }

    public class MFARCondition
    {
        public string SQL { get; set; }
        public string MaxRow { get; set; }
        public string Where { get; set; }
        public List<object> ParamList { get; set; }
        public string OrderBy { get; set; }
        public MFSQLSelect SelectObj { get; set; }

        public MFARCondition()
        {
            ParamList = new List<object>();
        }
    }

    public class MFActiveRecordReflect
    {
        public MFActiveRecordReflect()
        {

        }

        public static object GetValueByField(string fieldName, object data)
        {

            return MFReflect.GetProperty(data, fieldName);
        }

        public static object SetValueByField(string fieldName, object data, object value)
        {
            Type type = MFReflect.GetPropertyType(data, fieldName);

            if (type == typeof(Guid))
            {
                value = new Guid((string)value);
            }
            return MFReflect.SetProperty(data, fieldName, value);
        }

        public static bool IsHaveField(string fieldName, object data)
        {
            return MFReflect.IsHaveProperty(data, fieldName);
        }

        public static Type GetClassBaseType(Type classType, string className)
        {

            Type baseType = classType.BaseType;
            while (!baseType.Name.StartsWith(className, StringComparison.OrdinalIgnoreCase))
            {
                if (baseType.BaseType == typeof(Object)) return baseType;
            }
            return baseType;
        }

        public static string GetPrimaryKey(Type listType)
        {
            List<string> list = MFDataTransfer.GetPrimaryKeyFieldNames(listType);
            return list.Count > 0 ? list[0] : string.Empty;

        }

        public static object FindByPrimaryKeyOne(Type listType, params object[] args)
        {
            Type typeEntity = GetClassBaseType(listType, MFActiveRecordResource.MFActiveRecordBase);
            string na = typeEntity.Name;
            Type[] parameterTypes;
            object one = null;
            MethodInfo miFindOne;

            parameterTypes = new Type[1];
            parameterTypes[0] = typeof(object[]);

            miFindOne = typeEntity.GetMethod("FindByPrimaryKey", parameterTypes);
            Object[] parameters = new Object[1];
            parameters[0] = args;
            one = miFindOne.Invoke(null, parameters);

            return one;
        }

        public static object FindOne(Type listType, string where, params object[] args)
        {
            Type typeEntity = GetClassBaseType(listType, MFActiveRecordResource.MFActiveRecordBase);
            string na = typeEntity.Name;
            Type[] parameterTypes;
            object one = null;
            MethodInfo miFindOne;

            parameterTypes = new Type[2];
            parameterTypes[0] = typeof(string);
            parameterTypes[1] = typeof(object[]);
            miFindOne = typeEntity.GetMethod("FindOne", parameterTypes);
            Object[] parameters = new Object[2];
            parameters[0] = where;
            parameters[1] = args;
            one = miFindOne.Invoke(null, parameters);

            return one;
        }


        public static IList FindList(Type listType, string where,string orderBy, params object[] args)
        {
            Type typeEntity = GetClassBaseType(listType, MFActiveRecordResource.MFActiveRecordBase);
            Type[] parameterTypes;
            object list = null;
            MethodInfo miFindAll;

            if (string.IsNullOrEmpty(where))
            {
                if (string.IsNullOrEmpty(orderBy))
                {
                    parameterTypes = new Type[0];
                    miFindAll = typeEntity.GetMethod("FindAll", parameterTypes);
                    list = miFindAll.Invoke(null, null);
                }
                else
                {
                    parameterTypes = new Type[1];
                    parameterTypes[0] = typeof(string);

                    miFindAll = typeEntity.GetMethod("FindAllOrderBy", parameterTypes);
                    Object[] parameters = new Object[2];
                    parameters[0] = orderBy;
                    list = miFindAll.Invoke(null, parameters);

                }

                
            }
            else
            {

                if (string.IsNullOrEmpty(orderBy))
                {
                    parameterTypes = new Type[2];
                    parameterTypes[0] = typeof(string);
                    parameterTypes[1] = typeof(object[]);
                    miFindAll = typeEntity.GetMethod("FindAll", parameterTypes);
                    Object[] parameters = new Object[2];
                    parameters[0] = where;
                    parameters[1] = args;
                    list = miFindAll.Invoke(null, parameters);
                }
                else
                {
                    parameterTypes = new Type[3];
                    parameterTypes[0] = typeof(string);
                    parameterTypes[1] = typeof(string);
                    parameterTypes[2] = typeof(object[]);
                    miFindAll = typeEntity.GetMethod("FindAll", parameterTypes);
                    Object[] parameters = new Object[2];
                    parameters[0] = where;
                    parameters[1] = orderBy;
                    parameters[2] = args;
                    list = miFindAll.Invoke(null, parameters);

                }
               
            }

            return (IList)list;
        }

        public static IList FindList(Type listType, string where, params object[] args)
        {
            Type typeEntity = GetClassBaseType(listType, MFActiveRecordResource.MFActiveRecordBase);
            Type[] parameterTypes;
            object list = null;
            MethodInfo miFindAll;

            if (string.IsNullOrEmpty(where))
            {
                parameterTypes = new Type[0];
                miFindAll = typeEntity.GetMethod("FindAll", parameterTypes);
                list = miFindAll.Invoke(null, null);
            }
            else
            {
                parameterTypes = new Type[2];
                parameterTypes[0] = typeof(string);
                parameterTypes[1] = typeof(object[]);
                miFindAll = typeEntity.GetMethod("FindAll", parameterTypes);
                Object[] parameters = new Object[2];
                parameters[0] = where;
                parameters[1] = args;
                list = miFindAll.Invoke(null, parameters);
            }

            return (IList)list;
        }

        public static IList LazyLoad(Type listType, string propertyName)
        {
            object list = null;


            return (IList)list;
        }
    }

   
}
